package com.jikeshijian.concurrent;

import java.util.ArrayList;
import java.util.List;

/**
 * java 并发编程AQS 锁机制
 * 原子性的问题产生原因就是线程切换
 * 解决原子性的问题: 方案一锁中的互斥锁
 * 根据不同的场景的场景进行锁锁的颗粒化细分然后可以提高性能这种称之为细粒度锁
 * <p>
 * <p>
 * <p>
 * <p>
 * 锁机制的问题所在就是死锁的问题:
 * 解决死锁现在没有很好的解决方案 ,很多时候我们只能选择重启应用来解决问题
 * 解决死锁的方式现在主要的方式就是防患于未然 死锁的四种注意事项
 * 1. 互斥 ,共享资源只能被x和y 只能被一个线程所持有
 * 2. 占有且等待,T1线程获取共享资源x,在等待共享资源Y的时候,不释放共享资源X
 * 3. 不可抢占,其他线程不能强制抢占线程T1 所占有的资源
 * 4. 循环等待,线程T1等待T2占用的资源,线程T2等待线程T1的占用的资源,就是循环等待
 * 只要破坏上面一种文体就可以破坏死锁
 * 在开发的时候出现问题的时候出现问题:可以换个角度利用现实世间的模型解决来解决开发中的问题
 *
 * @author yihang.xu
 */

public class AqsDemo {
    /**
     * 创建出两把锁一把转入锁一把 转出锁当转出锁先加锁转出锁在加锁,当转入锁解锁后转出锁在释放
     *
     * @author yihang.xu
     */
    class Account {
        private int balance;

        // 转账
        void transfer(Account target, int amt) {
            // 锁定转出账户
            synchronized (this) {
                // 锁定转入账户
                synchronized (target) {
                    if (this.balance > amt) {
                        this.balance -= amt;
                        target.balance += amt;
                    }
                }
            }
        }
    }


    /**
     * 解决代码死锁问题
     *
     * @author yihang.xu
     */
    class Allocator {
        private List<Object> als =
                new ArrayList<>();

        // 一次性申请所有资源
        synchronized boolean apply(
                Object from, Object to) {
            if (als.contains(from) || als.contains(to)) {
                return false;
            } else {
                als.add(from);
                als.add(to);
            }
            return true;
        }

        // 归还资源
        synchronized void free(
                Object from, Object to) {
            als.remove(from);
            als.remove(to);
        }
    }

    class Accounts {
        // actr 应该为单例
        private Allocator actr;
        private int balance;

        // 转账
        void transfer(Account target, int amt) {
            // 一次性申请转出账户和转入账户，直到成功
            while (!actr.apply(this, target)) ;
            try {
                // 锁定转出账户
                synchronized (this) {
                    // 锁定转入账户
                    synchronized (target) {
                        if (this.balance > amt) {
                            this.balance -= amt;
                            target.balance += amt;
                        }
                    }
                }
            } finally {
                actr.free(this, target);
            }
        }
    }


    class AccountT {
        private int id;
        private int balance;

        // 转账
        void transfer(AccountT target, int amt) {
            AccountT left = this;
            AccountT right = target;
            if (this.id > target.id) {
                left = target;
                right = this;
            }
            // 锁定序号小的账户
            synchronized (left) {
                // 锁定序号大的账户
                synchronized (right) {
                    if (this.balance > amt) {
                        this.balance -= amt;
                        target.balance += amt;
                    }
                }
            }
        }
    }


}
